﻿
// 2019/2/19: 首个记录
// 2019/3/22: 时间戳赋值
// 2019/3/29: 添加注释
// 2020/1/14: 接口完备性

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ASEva;

namespace EnvSampleV2
{
    enum WeatherType
    {
        Unknown = 0, //未知
        Sunny = 1, //晴
        Cloudy = 2, //阴
        Rainy = 3, //雨
        Snowy = 4, //雪
        Foggy = 5, //雾
        Sand = 6, //沙尘
    };

    enum RoadType
    {
        Unknown = 0, //未知
        Highway = 1, // 高速路，无红绿灯，80~120KPH
        CityExpress = 2, // 城市快速路，无红绿灯，60~80KPH
        CityMain = 3, // 城市主干道，有红绿灯，推荐60KPH
        GeneralRoad = 4, // 一般道路，有红绿灯，推荐40KPH
        CountryRoad = 5, // 乡村道路，无红绿灯，~40KPH
    };

    enum SpotType
    {
        Unknown = 0,  //未知
        TollGate = 1, // 收费站
        ServiceArea = 2, // 服务区
        Tunnel = 3, // 隧道
        Accident = 4, // 事故
        Crossing = 5, // 路口
        Roundabout = 7, // 环岛
        HighwayEntrance = 8, // 高速入口
        HighwayExit = 9, // 高速出口
        Bridge = 10, // 桥
        ExpressEntrance = 11, // 快速路入口
        ExpressExit = 12, // 快速路出口
    }
    class Spot
    {
        public SpotType Type { get; set; }  //场所类型
        public double Distance { get; set; } //到场所的距离 m
    }

    enum TrafficStatus
    {
        Unknown = 0, // 未知
        Open = 1, // 畅通
        Slow = 2, // 缓慢
        Crowded = 3, // 拥挤
    };

    class EnvSample : Sample
    {
        public WeatherType WeatherType { get; set; }   //天气类型
        public double? Temperature { get; set; } // 温度 °C
        public double? PM25 { get; set; } // ug/m3
        public String RoadName { get; set; }  //道路名称
        public int? SpeedLimit { get; set; } // 道路限速 KPH
        public RoadType RoadType { get; set; }  //道路类型
        public double? Illumination { get; set; } // 光照强度 lux
        public double? WindSpeed { get; set; }  //风速 m/s
        public TrafficStatus TrafficStatus { get; set; }   //交通状况
        public List<Spot> Spots { get; set; } //场所列表

        public EnvSample()
        {
            Spots = new List<Spot>();
        }

        public static string Title
        {
            get
            {
                return "Road name size,Spot count,Weather,Temperature[°C],PM2.5[ug/m3],Speed limit[KPH],Road type,Illumination[lux],Wind speed[m/s],Traffic status,Spots and road name bytes...";
            }
        }

        public static string Protocol
        {
            get
            {
                return "env-sample-v2";
            }
        }

        public static string[] Protocols
        {
            get
            {
                return new string[] { "env-sample-v1", "env-sample-v2" };
            }
        }

        public override string GetGeneralSampleProtocol()
        {
            return Protocol;
        }

        public override string[] GetGeneralSampleProtocols()
        {
            return Protocols;
        }

        public override bool FromGeneralSample(GeneralSample sample)
        {
            if (sample.Protocol == "env-sample-v1")
            {
                if (sample.Values.Count < 1) return false;

                int roadNameSize = (int)sample.Values[0].number;
                if (sample.Values.Count != 13 + roadNameSize) return false;

                WeatherType = sample.Values[1].IsNumber() ? (WeatherType)(int)sample.Values[1].number : WeatherType.Unknown;
                Temperature = sample.Values[2].ToDouble();
                PM25 = sample.Values[3].ToDouble();
                SpeedLimit = sample.Values[4].IsNumber() ? (int?)(int)sample.Values[4].number : null;
                RoadType = sample.Values[5].IsNumber() ? (RoadType)(int)sample.Values[5].number : RoadType.Unknown;
                Illumination = sample.Values[6].ToDouble();
                WindSpeed = sample.Values[7].ToDouble();
                TrafficStatus = sample.Values[12].IsNumber() ? (TrafficStatus)(int)sample.Values[12].number : TrafficStatus.Unknown;

                var roadNameBin = new byte[roadNameSize];
                for (int i = 0; i < roadNameSize; i++)
                {
                    roadNameBin[i] = (byte)sample.Values[13 + i].ToInt().Value;
                }
                RoadName = Encoding.UTF8.GetString(roadNameBin);

                Base = sample.Base;
                Offset = sample.Offset;
                Timeline = sample.Timeline;

                return true;
            }
            else if (sample.Protocol == "env-sample-v2")
            {
                if (sample.Values.Count < 2) return false;

                int roadNameSize = (int)sample.Values[0].number;
                int spotCount = (int)sample.Values[1].number;

                if (sample.Values.Count != 10 + 2 * spotCount + roadNameSize) return false;

                WeatherType = sample.Values[2].IsNumber() ? (WeatherType)(int)sample.Values[2].number : WeatherType.Unknown;
                Temperature = sample.Values[3].ToDouble();
                PM25 = sample.Values[4].ToDouble();
                SpeedLimit = sample.Values[5].IsNumber() ? (int?)(int)sample.Values[5].number : null;
                RoadType = sample.Values[6].IsNumber() ? (RoadType)(int)sample.Values[6].number : RoadType.Unknown;
                Illumination = sample.Values[7].ToDouble();
                WindSpeed = sample.Values[8].ToDouble();
                TrafficStatus = sample.Values[9].IsNumber() ? (TrafficStatus)(int)sample.Values[9].number : TrafficStatus.Unknown;

                Spots = new List<Spot>();
                for (int i = 0; i < spotCount; i++)
                {
                    var spotType = sample.Values[10 + 2 * i].ToInt();
                    var spotDistance = sample.Values[10 + 2 * i + 1].ToDouble();
                    if (spotType != null && spotDistance != null)
                    {
                        Spots.Add(new Spot()
                            {
                                Type = (SpotType)spotType.Value,
                                Distance = spotDistance.Value,
                            });
                    }
                }

                var roadNameBin = new byte[roadNameSize];
                for (int i = 0; i < roadNameSize; i++)
                {
                    roadNameBin[i] = (byte)sample.Values[10 + 2 * spotCount + i].ToInt().Value;
                }
                RoadName = Encoding.UTF8.GetString(roadNameBin);

                Base = sample.Base;
                Offset = sample.Offset;
                Timeline = sample.Timeline;

                return true;
            }

            return false;
        }
    }
}
